import { KubernetesObject, V1ContainerPort, V1Service, V1ServiceSpec } from "@kubernetes/client-node"
import { K8SResourceType, KV, KVString, PlanContextData } from "yam-types"
import { AccessApproachConfig } from "../types"

export const composeService = (
  planData: PlanContextData, appAccess: AccessApproachConfig,
  serviceName: string, servicePort: number, containerPort: V1ContainerPort, nodePort?: number
): KubernetesObject => {
  const service: V1Service = {
    kind: K8SResourceType.Service,
    metadata: {
      name: serviceName,
      labels: {
        workload: planData.workloadName
      }
    },
    spec: Object.assign({}, appAccess.advancedFeatures?.serviceSpec, {
      type: nodePort ? "NodePort" : "ClusterIP",
      selector: {
        workload: planData.workloadName
      },
      ports: [{
        nodePort,
        port: servicePort,
        name: containerPort.name,
        protocol: containerPort.protocol,
        targetPort: new Object(containerPort.containerPort)
      }]
    } as V1ServiceSpec) as unknown as V1ServiceSpec
  }
  return service
}

export const composeLoadBalancer = (planData: PlanContextData, appAccess: AccessApproachConfig,
  serviceName: string, servicePort: number, containerPort: V1ContainerPort, settings: KV
): KubernetesObject => {
  const loadBalancer: V1Service = {
    kind: K8SResourceType.Service,
    metadata: {
      name: serviceName + '-lb',
      labels: {
        workload: planData.workloadName
      },
      annotations: Object.assign({}, settings.loadBalancerAnnotations, appAccess.advancedFeatures?.loadBalancerAnnotations) as KVString
    },
    spec: Object.assign({}, appAccess.advancedFeatures?.loadBalancerSpec, {
      type: "LoadBalancer",
      selector: {
        workload: planData.workloadName
      },
      loadBalancerSourceRanges: appAccess.advancedFeatures?.loadBalancerCIDRAlowList,
      ports: [{
        port: servicePort,
        name: containerPort.name,
        protocol: containerPort.protocol,
        targetPort: new Object(containerPort.containerPort)
      }]
    } as V1ServiceSpec) as unknown as V1ServiceSpec
  }
  return loadBalancer
}

export const composeHeadlessSvc = (planData: PlanContextData, appAccess: AccessApproachConfig,
  serviceName: string, servicePort: number, containerPort: V1ContainerPort
): KubernetesObject => {
  const loadBalancer: V1Service = {
    kind: K8SResourceType.Service,
    metadata: {
      name: appAccess.advancedFeatures?.headlessSvcName || (serviceName + '-headless'),
      labels: {
        workload: planData.workloadName
      }
    },
    spec: Object.assign({}, appAccess.advancedFeatures?.headlessServiceSpec, {
      type: "ClusterIP",
      selector: {
        workload: planData.workloadName
      },
      clusterIP: "None",
      publishNotReadyAddresses: !!(appAccess.advancedFeatures?.headlessServiceSpec?.publishNotReadyAddresses),
      ports: [{
        port: servicePort,
        name: containerPort.name,
        protocol: containerPort.protocol,
        targetPort: new Object(containerPort.containerPort)
      }]
    } as V1ServiceSpec) as unknown as V1ServiceSpec
  }
  return loadBalancer
}